package com.hu.bgp.framework.clientapi;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.ServiceDefTarget;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.TextArea;
import com.google.gwt.user.client.ui.Widget;
import com.hu.bgp.framework.util.FailureHandler;
import com.hu.bgp.framework.util.FailureHandlingCallback;
import com.hu.bgp.shared.BoardGameService;
import com.hu.bgp.shared.BoardGameServiceAsync;
import com.hu.bgp.shared.LeaveMessage;
import com.hu.bgp.shared.MinimumPlayersReachedMessage;
import com.hu.bgp.shared.NewServerToClientMessageEvent;
import com.hu.bgp.shared.OverviewUpdateMessage;

import de.novanic.eventservice.client.event.Event;
import de.novanic.eventservice.client.event.RemoteEventService;
import de.novanic.eventservice.client.event.listener.RemoteEventListener;

/**
 * Schrijf een subklasse van deze klasse om een client (game UI) te
 * implementeren.
 * 
 * @author ejvos
 */
public abstract class Client implements FailureHandler, EntryPoint
{
	private BoardGameServiceAsync bgpService;
	private ClientGameContext clientGameContext;
	private SpinPanel spinPanel = new SpinPanel();
	private Button leaveButton = new Button("Leave");
	private TextArea overview = new TextArea();
	private boolean gameStarted = false;

	public final void onModuleLoad()
	{
		// get a binding to the servlet
		bgpService = GWT.create(BoardGameService.class);
		ServiceDefTarget target = (ServiceDefTarget) bgpService;
		target.setServiceEntryPoint("/bgp/bgpService");

		// grab the context
		bgpService.getClientGameContext(new FailureHandlingCallback<ClientGameContext>(this)
		{
			public void onSuccess(ClientGameContext result)
			{
				clientGameContext = result;

				// listeners for incoming game-wide events
				AllDomainEventListener listener = new AllDomainEventListener();
				RemoteEventService theRemoteEventService = BgpRemoteEventServiceFactory.getInstance().getRemoteEventService();
				theRemoteEventService.addListener(clientGameContext.getGameDomain(), listener);
				//theRemoteEventService.addListener(clientGameContext.getUserDomain(), listener);

				spinPanel.show();

				// call child's class onModuleLoad
				onModuleLoad2();
			}
		});

		leaveButton.addClickHandler(new ClickHandler()
		{
			public void onClick(ClickEvent event)
			{
				LeaveMessage message = new LeaveMessage(getUserUuid());
				sendMessageAndIgnoreOutcome(message);
			}
		});
	}

	protected abstract void onModuleLoad2();

	private void handleMessage(ServerToClientMessage message)
	{
		if (message instanceof OverviewUpdateMessage)
		{
			OverviewUpdateMessage oum = (OverviewUpdateMessage) message;
			overview.setText(oum.getOverview());
		}
		else if (message instanceof MinimumPlayersReachedMessage)
		{
			spinPanel.hide();

			// set up the playarea
			RootPanel rootPanel = RootPanel.get("content");
			rootPanel.clear();
			rootPanel.add(getPlayArea());
			RootPanel overviewPanel = RootPanel.get("overview");
			overviewPanel.clear();
			overviewPanel.add(leaveButton);
			overviewPanel.add(overview);

			gameStarted = true;
		}
		else
		{
			handleMessage2(message);
		}
	}

	protected abstract void handleMessage2(ServerToClientMessage message);

	protected abstract Widget getPlayArea();

	protected void sendMessageAndIgnoreOutcome(ClientToServerMessage message)
	{
		bgpService.handleMessage(message, new FailureHandlingCallback<Void>(this)
		{
			public void onSuccess(Void result)
			{
			}
		});
	}

	protected String getUserUuid()
	{
		return clientGameContext.getUserUuid();
	}

	private class AllDomainEventListener implements RemoteEventListener
	{
		public void apply(Event event)
		{
			if (event instanceof NewServerToClientMessageEvent)
			{
				if (!gameStarted)
				{
					spinPanel.hide();

					// set up the playarea
					RootPanel rootPanel = RootPanel.get("content");
					rootPanel.clear();
					rootPanel.add(getPlayArea());
					RootPanel overviewPanel = RootPanel.get("overview");
					overviewPanel.clear();
					overviewPanel.add(leaveButton);
					overviewPanel.add(overview);

					gameStarted = true;
				}
				NewServerToClientMessageEvent messageEvent = (NewServerToClientMessageEvent) event;
				handleMessage(messageEvent.getMessage());
			}
		}
	}
}
